package com.yanqu.road.server;

import com.yanqu.road.NettyMgr;
import com.yanqu.road.connect.ServerLinkControl;
import com.yanqu.road.dao.db.DBManager;
import com.yanqu.road.dao.db.DBTableInfoMgr;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.entity.autodata.AutoDataObject;
import com.yanqu.road.logic.bussiness.servercenter.ServerBussiness;
import com.yanqu.road.logic.config.AreaServerConfig;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.redis.RedisManger;
import com.yanqu.road.server.command.CommandControl;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.ServerType;
import com.yanqu.road.utils.net.ServerNetConfig;
import com.yanqu.road.utils.net.ServerNetConfigHelper;
import com.yanqu.road.utils.string.StringUtils;
import io.netty.channel.ChannelHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;

public abstract class TempServer {

	public static Logger tempServerLogger = LogManager.getLogger("OPEN_AND_CLOSE");

	private static Logger logger = LogManager.getLogger(TempServer.class.getName());

	// 全局配置路径
	protected static String cfgPath;

	// 上一个组件初始化时间
	protected long lastComponentInitTime;

	// 服务端代码版本
	private String backendVersion = "";

	// 定时器线程池
	protected static ScheduledExecutorService timerScheduledExecutorService;

	// 服务器类型
	protected int sType;

	// 服务器id
	protected long sid;
	protected DBTableInfoMgr dbTableInfoMgr;


	public abstract List<TempMgr> getMgrList();

	protected boolean initTempMgrList() {
		return initTempMgrList(getMgrList());
	}

	protected boolean initTempMgrList(List<TempMgr> mgrList) {
		Set<Class> mgrClassSet = new HashSet<>();
		try {
			if (null != mgrList) {
				for (TempMgr mgr : mgrList) {
					Class<? extends TempMgr> clazz = mgr.getClass();
					if (mgrClassSet.contains(clazz)) {
						logger.error("sameMgr init.  {}", clazz.getSimpleName());
						return false;
					}
					boolean result = initGameModule(mgr.init(), "load " + mgr.getClass().getName());
					if(!result){
						logger.error("load " + mgr.getClass().getName()+" fail");
						return false;
					}
					mgrClassSet.add(clazz);
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		}
		return true;
	}

	protected boolean initNetWorkConfig() {
		return ServerNetConfigHelper.init(DBManager.getNetConfigFromDb());
	}

	protected void refreshGameConfig() {
		GameConfig.reloadGameGlobalConfig();
	}

	public boolean start() {
		String versionInfo = "v4.0.0_release";
		Properties properties = readGitProperties();
		if (properties != null) {
			String property = properties.getProperty("git.branch");
			if (property != null) {
				versionInfo = properties.getProperty("git.branch");
				backendVersion = properties.getProperty("git.branch");
			}
		}
		logger.info("backend code version . " + versionInfo);
		System.err.println("backend code version . " + versionInfo);

		lastComponentInitTime = System.currentTimeMillis();

		if (!initGameModule(CommandControl.loadCommand(), "load all commands")) {
			return false;
		}

		if (!initGameModule(AutoDataObject.loadAllClazzInfo(), "load all autoDataObject")) {
			return false;
		}

		if (!initGameModule(ConfigHelper.initConfig(cfgPath), "load global config")) {
			return false;
		}

		if (!initGameModule(DBManager.initConfig(ConfigHelper.getValue("db.path")), "load user center mysql config"))
			return false;

		if (!initGameModule(DBManager.initGameDbConfig(sType), "load game db mysql config")) {
			return false;
		}

		if (!initGameModule(initNetWorkConfig(), "load network config")) {
			return false;
		}

		sid = Long.parseLong(ConfigHelper.getValue("serverId"));

        // 跨地区服务器没有这些操作
        if (sType != ServerType.SERVER_CHANNEL) {

            refreshGameConfig();

			int channelId = 0;
			ServerInfo serverInfo = ServerBussiness.getServerInfoByServerId(sid);
			if (null != serverInfo) {
				channelId = serverInfo.getChannelId();
			} else {
				if (!StringUtils.isNullOrEmpty(ConfigHelper.getValue("channelId"))) {
					channelId = ConfigHelper.getInt("channelId");
				}
			}

            ChannelConfig.reloadChannelConfig(channelId);

            //启动redis
            RedisManger.initConfig(ConfigHelper.getValue("redis.path"));
        } else {
			//跨域服务器配置刷新 7.5新增
			AreaServerConfig.reloadAreaServerConfig(sid);
		}

		if (!initTempMgrList()) {
			return false;
		}

		return true;
	}



	protected boolean stop() {
		NettyMgr.stop();
		System.exit(0);
		return true;
	}

	protected boolean stopWithLogger() {
		logger.info("------------");
		logger.info("------------");
		logger.info("------------");
		logger.info("------------");
		NettyMgr.stop();
		logger.info("notify process stop success!");

		tempServerLogger.info("notify process stop success!");
		Runtime.getRuntime().halt(1);
		return true;
	}

	protected boolean initGameModule(boolean initResult, String gameModuleName) {
		long nowTime = System.currentTimeMillis();
		if (initResult) {
			logger.info(gameModuleName + " init succeed, cost time: {} ms", (nowTime - lastComponentInitTime));
		} else {
			logger.error(gameModuleName + " init ");
		}
		lastComponentInitTime = nowTime;
		return initResult;
	}

	/**
	 * 删除单个文件
	 * @param   sPath    被删除文件的文件名
	 * @return 单个文件删除成功返回true，否则返回false
	 */
	public static boolean deleteFile(String sPath) {
		boolean flag = false;
		File file = new File(sPath);
		// 路径为文件且不为空则进行删除
		if (file.isFile() && file.exists()) {
			file.delete();
			flag = true;
		}
		return flag;
	}


	private Properties readGitProperties() {
		InputStream inputStream = null;
		try {
			ClassLoader classLoader = getClass().getClassLoader();
			inputStream = classLoader.getResourceAsStream("git.properties");
			Properties gitProperties = new Properties();
			gitProperties.load(inputStream);
			return gitProperties;
		} catch (Exception e) {
			logger.error("get git version info fail", e);
		} finally {
			try {
				if (inputStream != null) {
					inputStream.close();
				}
			} catch (Exception e) {
				logger.error("close inputStream fail", e);
			}
		}
		return null;
	}

	protected boolean initNetty(ChannelHandler handler, int type) {
		ServerNetConfig serverNetConfig = ServerNetConfigHelper.getServerNetConfig(type, 0);
		if (serverNetConfig == null) {
			logger.error("can not found serverNetConfig config");
			return false;
		}
		boolean result = NettyMgr.start(serverNetConfig.getPort(), handler);
		if (!result) {
			return false;
		}
		ServerLinkControl.initServerLinkControl(ServerNetConfigHelper.getAgentCount());
		return true;
	}

	public static ScheduledExecutorService getTimerExecutorService() {
		return timerScheduledExecutorService;
	}

	public int getServerType() {
		return sType;
	}

	public void setServerType(int serverType) {
		this.sType = serverType;
	}

	public long getServerId() {
		return sid;
	}

	public void setServerId(long serverId) {
		this.sid = serverId;
	}

	public String getBackendVersion() {
		return backendVersion;
	}

	public void setBackendVersion(String backendVersion) {
		this.backendVersion = backendVersion;
	}



	public DBTableInfoMgr getDbTableInfoMgr() {
		return dbTableInfoMgr;
	}

	public void setDbTableInfoMgr(DBTableInfoMgr dbTableInfoMgr) {
		this.dbTableInfoMgr = dbTableInfoMgr;
	}
}
